#include"ppSpline.h"
#include<iostream>
#include<fstream>  
#include<sstream> 
#include<cmath>
#include<string>
using namespace std;

// 总采样点个数
const int sample_num = 800;

// 将心形曲线上下拆分成两个函数图像的并
double f_above(double x){
    return 2.0 * (sqrt(abs(x)) + sqrt(3-x*x)) / 3.0;
}
double f_under(double x){
    return 2.0 * (sqrt(abs(x)) - sqrt(3-x*x)) / 3.0;
}

// 添加与y轴对称的样本点到txt文件中
void add_sym_pts(const string& filename){  
    ifstream inputFile(filename);  
    ofstream tempFile("temp.txt");  
  
    if (!inputFile.is_open()) {  
        cerr << "Error: Unable to open the input file." << std::endl;  
        return;  
    }  
  
    if (!tempFile.is_open()) {  
        cerr << "Error: Unable to create the temporary file." << std::endl;  
        return;  
    }  
  
    vector<pair<double, double>> numbers;  
  
    string line;  
    while (getline(inputFile, line)) {  
        istringstream iss(line);  
        double num1, num2;  
        iss >> num1 >> num2;  
        numbers.emplace_back(num1, num2);  
    }  
  
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {  
        tempFile << it->first << " " << it->second << std::endl;  
    }  
  
    for (auto it = numbers.rbegin(); it != numbers.rend(); ++it) {  
        tempFile << -it->first << " " << it->second << std::endl;  
    }  
  
    inputFile.close();  
    tempFile.close();  
  
    remove(filename.c_str());  
    rename("temp.txt", filename.c_str()); 
}  

// 存储心形曲线的样本点到txt文件中
void heartcurve_data(){
    double x;
    double delta = 4 * sqrt(3) / sample_num;

    string filename = "output/ProblemE_data/heartcurve.txt";    //创建文件名  
    ofstream outputFile(filename);  //创建文件流对象
    if(outputFile.is_open()){
        for(x = -sqrt(3); x < sqrt(3); x += delta){
            outputFile << x << " " << f_above(x) << endl;//导出到txt文件中
        }
        for(x = sqrt(3); x > -sqrt(3); x -= delta){
            outputFile << x << " " << f_under(x) << endl;//导出到txt文件中
        }
        outputFile << -sqrt(3) << " " << f_above(-sqrt(3));
        outputFile.close(); //关闭文件  
        cout << "File " << filename << " created and written successfully.\n";
    }
    else{  
        cout << "Error creating file: " << filename << endl;  
    }
}

// 传入散点,将拟合得的样条的样本点记录到txt文件中.
void spline_data(vector<vector<double>> &S){
    int N = S.size();
    int n = 2 * (N-1);
//    cout << "拟合平面散点, n = " << n << endl;
    vector<ppSpline<3>> pp_dis_point = solver(S, natural); 
//    for(auto eles : pp_dis_point){
//        eles.print_ppForm();
//    }
    string name = "output/ProblemE_data/" + to_string(n) + "knots.txt";
    ofstream file(name);
    if(file.is_open()){
        print_dis_pt_data(pp_dis_point, sample_num/(N-1), file);
        file.close();
        cout << "File " << name;
        cout << " created and written successfully.\n";
    }
    else{  
        cout << "Error creating file: " << name << ".\n";  
    }
    add_sym_pts(name);
}


int main(){
    cout << "-----ProblemE-----\n";
    
    heartcurve_data();

    ifstream input("input/inputE.txt");  
    if(!input.is_open()){  
        cerr << "Unable to open input file!" << endl;  
        exit(-1);
    }

    int num_of_entries;
    input >> num_of_entries;
    vector<vector<double>> knots10;
    for(int i = 0; i < num_of_entries; i++){
        double x, y;
        input >> x >> y;
        knots10.push_back({x, y});
    }
    spline_data(knots10);

    {
        vector<vector<double>> character_pt;
        input >> num_of_entries;
        for(int i = 0; i < num_of_entries; i++){
            double x, y;
            input >> x >> y;
            character_pt.push_back({x, y});
        }
        
        int interval_num = character_pt.size() - 1;
        vector<vector<double>> knots40;
        const int pts_num = 4;
        for(int i = 0; i < interval_num; i++){
            double x = character_pt[i][0];
            knots40.push_back(character_pt[i]);
            double delta = (character_pt[i+1][0] - character_pt[i][0]) 
                                                    / (pts_num+1);
            for(int j = 0; j < pts_num; j++){
                x += delta;
                if(i < interval_num / 2)
                    knots40.push_back({x,f_under(x)});    
                else
                    knots40.push_back({x,f_above(x)});    
            }
        }
        knots40.push_back(character_pt[interval_num]);
        spline_data(knots40);
    }
    
    {
        vector<vector<double>> character_pt;
        input >> num_of_entries;
        for(int i = 0; i < num_of_entries; i++){
            double x, y;
            input >> x >> y;
            character_pt.push_back({x, y});
        }

        int interval_num = character_pt.size() - 1;
        vector<vector<double>> knots160;       
        for(int i = 0; i < interval_num; i++){
            double x = character_pt[i][0];
            int pts_num = 13;
            if(i == 1 || i == interval_num - 2)
                pts_num = (74 - 4 * pts_num) / 2;
            knots160.push_back(character_pt[i]);
            double delta = (character_pt[i+1][0] - character_pt[i][0]) 
                                                    / (pts_num+1);
            for(int j = 0; j < pts_num; j++){
                x += delta;
                if(i < interval_num / 2)
                    knots160.push_back({x,f_under(x)});    
                else
                    knots160.push_back({x,f_above(x)});    
            }
        }
        knots160.push_back(character_pt[interval_num]);
        spline_data(knots160);
    }
    

    return 0;
}